#ifndef __GOSSIP_H_
#define __GOSSIP_H_

#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include "tree.h"   /* this module depends on tree.h of freebsd head files */
#include "queue.h"

/***************************************************
 * user customize
 ***************************************************/

#define GSP_MALLOC(size)	malloc(size)    /* tell the module how to get memory */
#define GSP_FREE(ptr)       free(ptr)       /* tell the module how to free memory */


#define GSP_HOST_NAME_LEN	50
#define GSP_BUF_LEN         256
#define GSP_HOST_LIMIT      3   /* find and select 3 peers to send each loop */

/* if the remote peer do not reaponse more than GSP_TEST_TIMES times
 * it will be removed from the known peer list */
#define GSP_TEST_TIMES      1   

/* indicates how long should this peer waits for another peer's response.
 * PEER_TIMEOUT_SEC is in SECONDS.
 * PEER_TIMEOUT_USEC is in uSECONDS.
 * the sum of the two value is the final waiting time. */
#define PEER_TIMEOUT_SEC    3
#define PEER_TIMEOUT_USEC   0

#define GSP_DEBUG
//#define GSP_DEBUG_ADVANCED

/***************************************************
 * error definates. DO NOT MODIFY most of the time.
 ***************************************************/

#define GSP_PEER_ADD_OK         1
#define GSP_PEER_ADD_FAILED     -1
#define GSP_PEER_REMOVE_OK      1
#define GSP_PEER_REMOVE_FAILED  -1
#define GSP_ROUTE_OK            1
#define GSP_ROUTE_FAILED        -1
 

/***************************************************
 * internal definition. DO NOT MODIFY
 ***************************************************/

typedef struct local_peer_info
{
	char l_host[GSP_HOST_NAME_LEN + 1];
	int l_port;
	int l_ttl;
	int l_peerid;
    char init_host[GSP_HOST_NAME_LEN + 1];
    int init_port;

}LOCAL_PEER;


typedef struct _gossip_node
{
	char r_host[GSP_HOST_NAME_LEN + 1];
	int r_port;
	int r_peerid;

    uint64_t last_cmd_id;
    int remove_flag;

    RB_ENTRY(_gossip_node) node_entries;   /* peer node linker */
    STAILQ_ENTRY(_gossip_node) stq_entry;
	
}PEER_NODE;


typedef struct _gossip_handler
{
    LOCAL_PEER *localpeer;
    pthread_rwlock_t tree_lock;      /* read-write lock of red-black tree */
    pthread_rwlock_t stq_lock;      /* read-write lock of link list */

    uint64_t last_command;
    RB_HEAD(RB_TREE, _gossip_node) rb_tree;
    STAILQ_HEAD(STQ_LIST, _gossip_node) stq_list;
}GOSSIP_HANDLER;


/***************************************************
 * functions. DO NOT MODIFY
 ***************************************************/

GOSSIP_HANDLER *
gossip_init(char *init_host, int init_port, char *current_host, 
						int current_port, int default_ttl, int peer_id);

int gossip_addpeer(GOSSIP_HANDLER *handler, char *r_host, int r_port, int r_peerid);
int gossip_rmpeer(GOSSIP_HANDLER *handler, int r_peerid, int addto_list);
int gossip_route(GOSSIP_HANDLER *handler, char *msg, size_t msglen, uint64_t cmdid, int src_peerid, int sender_id);
int gossip_clean(GOSSIP_HANDLER *handler);
void gossip_disreg(GOSSIP_HANDLER *handler);

int gossip_connect(char *host, int port);
ssize_t gossip_writen(int fd, const void *vptr, ssize_t n);

#endif 



